package com.frank.oj.core.receiver;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.frank.model.dto.TestJudgeReq;
import com.frank.model.dto.ToJudgeDTO;
import com.frank.model.entity.contest.ContestRecord;
import com.frank.model.entity.judge.Judge;
import com.frank.oj.constant.Constants;
import com.frank.oj.core.dispatcher.Dispatcher;
import com.frank.oj.service.entity.contest.ContestRecordEntityService;
import com.frank.oj.service.entity.judge.JudgeEntityService;
import com.frank.oj.utils.RedisUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Objects;

/**
 * @author frank
 * @Date 2024/4/24
 */
@Component
public class JudgeReceiver extends AbstractReceiver {
    @Resource
    private Dispatcher dispatcher;

    @Resource
    private RedisUtils redisUtils;

    @Resource
    private JudgeEntityService judgeEntityService;

    @Resource
    private ContestRecordEntityService contestRecordEntityService;

    @Override
    public String getTaskByRedis(String queue) {
        long size = redisUtils.lGetListSize(queue);
        if (size > 0) {
            return (String) redisUtils.lrPop(queue);
        } else {
            return null;
        }
    }

    @Override
    public void handleJudgeMsg(String taskStr, String queueName) {
        // 测试提交
        if (Constants.Queue.TEST_JUDGE_WAITING.getName().equals(queueName)) {
            TestJudgeReq testJudgeReq = JSONUtil.toBean(taskStr, TestJudgeReq.class);
            dispatcher.dispatch(Constants.TaskType.TEST_JUDGE, testJudgeReq);
        } else {
            JSONObject task = JSONUtil.parseObj(taskStr);
            Long judgeId = task.getLong("judgeId");
            Judge judge = judgeEntityService.getById(judgeId);

            if (judge != null) {
                // 调度评测时发现该评测任务被取消，则结束评测
                if (Objects.equals(judge.getStatus(), Constants.Judge.STATUS_CANCELLED.getStatus())) {
                    if (judge.getCid() != 0) {
                        UpdateWrapper<ContestRecord> updateWrapper = new UpdateWrapper<>();
                        // 取消评测，不罚时也不算得分
                        updateWrapper.set("status", Constants.Contest.RECORD_NOT_AC_NOT_PENALTY.getCode());
                        updateWrapper.eq("submit_id", judge.getSubmitId());
                        contestRecordEntityService.update(updateWrapper);
                    }
                } else {
                    String token = task.getStr("token");
                    dispatcher.dispatch(Constants.TaskType.JUDGE, new ToJudgeDTO().setJudge(judge).setToken(token).setRemoteJudgeProblem(null));
                }
            }
        }
        // 继续处理等待队列
        processWaitingTask();
    }

    /**
     * 等待判题的队列：优先处理比赛的提交任务 -> 其次处理普通提交的提交任务 -> 最后处理在线调试的任务
     */
    @Async("judgeTaskAsyncPool")
    public void processWaitingTask() {
        handleWaitingTask(Constants.Queue.CONTEST_JUDGE_WAITING.getName(),
                Constants.Queue.GENERAL_JUDGE_WAITING.getName(),
                Constants.Queue.TEST_JUDGE_WAITING.getName());
    }
}
